home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 4
/
Apprentice-Release4.iso
/
Languages
/
Mops 2.7
/
Mops ƒ
/
Base
< prev
next >
Wrap
Text File
|
1995-10-09
|
13KB
|
511 lines
\ Sept 92 mrh New words etc. moving closer to ANSI standard
\ Jul 93 mrh Select{ removed - replaced by Select[ in caseMod
false value ECHO? \ echo load to screen?
cr .( loading Base...)
\ (* ... *) defines a multi-line comment, which can be very useful. Many
\ Pascal compilers use these symbols - I thought it better not to use
\ the C-style /* ... */ since */ already has a meaning.
\ A useful improvement to the typical Pascal implementation is to keep a
\ level count so that this kind of comment can be nested.
: (*
1 \ initial level count
BEGIN
Mword count 2dup
" (*" s=
IF 2drop 1 + \ increment level count
ELSE
" *)" s=
IF 1 - \ decrement level count
?dup 0EXIT \ and if zero, we're done
THEN
THEN
AGAIN ; immediate
\ We redefine a few useful words to take advantage of our optimization.
: 1+ state IF 1 postpone literal postpone + ELSE 1 + THEN ; immediate
: 2+ state IF 2 postpone literal postpone + ELSE 2 + THEN ; immediate
: 3+ state IF 3 postpone literal postpone + ELSE 3 + THEN ; immediate
: 4+ state IF 4 postpone literal postpone + ELSE 4 + THEN ; immediate
: 1- state IF 1 postpone literal postpone - ELSE 1 - THEN ; immediate
: 2- state IF 2 postpone literal postpone - ELSE 2 - THEN ; immediate
: 3- state IF 3 postpone literal postpone - ELSE 3 - THEN ; immediate
: 4- state IF 4 postpone literal postpone - ELSE 4 - THEN ; immediate
: 2* state IF 1 postpone literal postpone << ELSE 1 << THEN ; immediate
: 2/ state IF 1 postpone literal postpone a>> ELSE 1 a>> THEN ; immediate
: 4* state IF 2 postpone literal postpone << ELSE 2 << THEN ; immediate
: 4/ state IF 2 postpone literal postpone a>> ELSE 2 a>> THEN ; immediate
\ ANSI words
: CELL+ state IF postpone 4+ else 4 + THEN ; immediate
: CELL- state IF postpone 4- else 4 - THEN ; immediate
: CELLS state IF 2 postpone literal postpone << ELSE 2 << THEN ; immediate
: CHAR+ state IF postpone 1+ else 1 + THEN ; immediate
: CHARS ; immediate
4 constant 1CELL \ Not ANSI, but useful
: RECURSE curr-def compile, ; immediate
: SAVE-INPUT
src-start src-len >in @ source-id 4 ;
: RESTORE-INPUT
dup 4 <> IF true EXIT THEN
drop
-> source-id >in ! -> src-len -> src-start false ;
\ =========================
\ These can be useful:
: UMAX 2dup u> IF drop ELSE nip THEN ;
: UMIN 2dup u< IF drop ELSE nip THEN ;
\ .H and U.H print a number in hex, signed and unsigned respectively.
: .H base >r hex . r> -> base ;
: U.H base >r hex u. r> -> base ;
0 constant Z
: NULLOSSTR ['] z ;
: @WORD \ ( -- addr ) Retrieves next blank-delimited word from input stream.
BL word ;
: LIT \ ( n -- ) A state-smart version of LITERAL. Corresponds
\ to LITERAL in Fig-Forth or original Neon, whereas our
\ present LITERAL is Forth-83/ANSI.
state IF postpone literal THEN ; immediate
: 0, 0 , ; \ Compiles an empty cell
: @VAL intrp1 ; \ Compiles a number from input stream
: 'TYPE \ ( -- 4bytes ) OS type literal
pad 4 bl fill @word count 4 min
pad swap cmove pad @ postpone lit ; immediate
create BUF255 256 allot \ buffer for string operations
: >STR255 \ ( addr len addr -- addr )
\ Converts a string to a Str255 at addr
dup >r place r> ;
: STR255 \ ( -- ^buf255 )
buf255 >str255 ;
: $ \ State-smart HEX literal word
base >r
hex Mword number postpone lit
r> -> base ; immediate
: LITW \ ( n -- )
$ 3D3C w, w, ;
: W intrp1 litw ; immediate
(* Trap compilation. When we're fully native on the PowerPC this will
become totally obsolete...
*)
: SAVA5 postpone doSavA5 ;
: RSTA5
$ CD4F w, \ exg a6,a7
$ 2A5F w, ; \ move.l (a7)+,a5
: (TRAP$) \ ( trap# -- ) Compiles a call to the given trap.
SavA5 w, RstA5 ;
: TRAP$ \ ( --<trap#> )
base >r
hex intrp1 (trap$)
r> -> base ; immediate
: (FDOS$) \ ( trap# -- )
$ 205E w, \ move.l (a6)+,a0 ; FCB pointer
SavA5 w, RstA5
$ 48C0 w, \ ext.l d0 ; Result
$ 2D00 w, ; \ move.l d0,-(a6)
: FDOS$ \ ( --<trap#> )
base >r
hex intrp1 (fdos$)
r> -> base ; immediate
\ ==================
\ Once we're compiling PPC code, we have to keep the code and data areas
\ distinct. DP points to the data area, so we now add CDP pointing to
\ the code area.
0 value CDP
: code, PPC? IF CDP ! 4 ++> CDP ELSE , THEN ;
: codeW, PPC? IF CDP w! 2 ++> CDP ELSE w, THEN ;
: codeC, PPC? IF CDP c! 1 ++> CDP ELsE c, THEN ;
' null vect PPC_HEADER
\ ==================
0 value ResRefNum
: OpenResFile \ ( addr len -- ) Opens named resource file
>r >r word0 r> r> str255
trap$ a997 i->l \ call OpenResFile
dup -> ResRefNum
-1 = abort" resource file open failed" ;
: CloseResFile \ ( -- )
ResRefnum makeint trap$ a99a ;
: OPENMR \ Opens the Mops system resource file if necessary.
MRopen? ?EXIT \ Do nothing if already open
instld? ?EXIT \ or if this is an installed application
" mops.rsrc" OpenResFile
true -> MRopen? ;
: CHAR @word 1+ c@ ; \ ANSI - replaces ASCII
: [CHAR] @word 1+ c@ postpone literal ; immediate
: & \ ( -- c ) A shorter state-smart version.
@word 1+ c@ postpone lit ; immediate
: GETSTRING \ ( resID -- addr len ) Get the string with resource ID
openMR
0 swap makeint trap$ a9ba \ call getString
dup if @ count else 0 then ;
: (TSTR) \ ( id# -- ) Prints string with given resID.
getString type ;
: X ['] (tstr) -> tstr ; \ We can't do -> outside a defn till Args loaded
x forget x
\ Our normal error action is to call DIE with an error number. DIE calls
\ SvErr to save the error info, then THROWs the error number. If no error
\ handler has been installed, or only handlers which don't want that number
\ and re-THROW it, the default action for THROW occurs. This calls DFLT-DIE.
: (DDIE) \ ( n -- )
setFwind
+echo 0 -> (err#) \ Clear error indicator from AppleEvents
dflt-err ; \ Display error info and abort
: x ['] (ddie) -> dflt-die ;
x forget x
: ?ERROR \ ( b -- ) Aborts and prints resource string if true.
\ Usage: ?error 999
postpone if
intrp1 ( get err# ) postpone literal postpone die
postpone then ; immediate
: TYPE# \ Prints string for id# in stream
intrp1 postpone lit postpone (tStr) ; immediate
: (.RSTR) \ ( -- ) print "Msg# ..." then string with given resID
." Msg# " dup . ." : " (tStr) ;
: MSG# \ usage: " Msg# <number>"
intrp1 postpone lit postpone (.rStr) ; immediate
\ ============ Resources ===========
: GETRES \ ( type resID -- handle )
0 down makeint trap$ a9a0 ; \ call GetResource
\ ( -- #cells)
: RDEPTH rp0 rp@ - 4/ 2- ;
: ?RDEPTH rp@ sp0 20 + < ?error 116 ; \ err if rtn stk about to
\ collide with data stk
\ ========== Type checking ===========
\ Sometimes we want to check that a non-object parameter to a word is of a
\ certain type. We give it a unique type code and use TYPCHK.
: TYPCHK <> ?error 179 ;
\ ========== Forward definitions ===========
: X setfWind +echo
cr ." From " r@ .id 2 spaces r@ .h cr 109 die ;
: FORWARD
colHdr
$ 487AFFFE , \ pea (start of this instrn)
['] x here 6 allot
(patch) ;
: :F 301
here ' (patch) :noname ;
: ;F (;) 301 ?defn ; immediate
forward BLD \ Used in CLASS. Needs to be down here so we never
\ refer to it with a short branch. Kludge?
\ Commonly needed error words. These are forward defined - the main
\ application should provide a sensible definition, with a nice friendly
\ alert box, to tell the user in a nice friendly way that things are up
\ the creek.
forward NOMEM \ Call when (not if!) we run out of memory.
forward I/O_ERR \ ( err# -- ) Call when there's an I/O error.
: OK? \ ( rc -- ) A useful word to use after an I/O op.
?dup 0EXIT I/O_err ;
\ ========= :PROC and ;PROC ============
: :PROC
colHdr here 6 allot
['] procEntry swap 6 aligned_move
:noname 303 ; immediate
: ;PROC immediate
postpone procExit (;)
303 ?defn ;
\ ======== Various utility words needed later =========
\ BECOME allows restarting at a given word, with all stacks
\ empty. This is necessary in menu handlers and other areas
\ that could create indefinite nesting situations.
' quit vect BECOMECFA
: BE sp0 sp! rp0 rp! becomeCfa quit ;
: (BE) -> becomeCfa be ;
: BECOME \ Usage: Become newWord - compiles code to Be at runtime
state
IF postpone ['] postpone (be)
ELSE ' -> becomeCfa be
THEN ; immediate
: DATETIME
$ 20C @ ;
\ ============ Tables, lists etc. ===============
(* With Mops 2.5 we're trying to be consistent with the way we delimit
various kinds of lists with { ... }. No, we're not trying to copy C,
but let's at least follow the "principle of minimum astonishment"!
Thus, with words like xts{, we'll allow a variant "xts {" where you
can put a space before the "{". This is very easy to implement, so
why not?
*)
forward { immediate
: GOBBLE{ \ gobbles a "{" which must follow as a separate word.
' ['] { <> ?error 113 ; \ "{" expected
: ) 123 die ; immediate \ ") read when no list is current"
: (}) 123 die ; immediate \ "unmatched }"
' (}) vect } \ } will mean different things in different
\ contexts.
: }OR)? \ ( cfa -- cfa b )
dup ['] } = over ['] ) = or ;
(*
: TABLE
<BUILDS 0 w, here 112
DOES> length ;
: END_TABLE
112 ?pairs
here over - \ table length (excluding length field)
swap 2- w! ; \ store in length field
*)
0 value CNT
: (LITS) \ stack compiled list of values starting at IP
w@(ip) ( count ) dup -> cnt
4* r> tuck + dup >r swap
do i @abs 4 +loop
cnt ;
: XTS{ \ State-smart word to compile or stack a list
\ of xts. Pulls words from stream, until "}".
state IF postpone (lits) here 0 w, THEN
0
BEGIN ' }or)?
NWHILE state IF reloc, else swap THEN 1+
REPEAT
drop state IF swap w! THEN ; immediate
: CFAS{ postpone xts{ ; immediate \ Synonyms for compatibility
: CFAS( postpone xts{ ; immediate
: XTS gobble{ postpone xts{ ; immediate
: RESERVE \ ( len -- ) Allot and clear.
here over erase allot ;
(* SCON defines a string constant. Usage:
scon <name> "a string"
Runtime: ( -- addr len )
Change from Neon: the first nonblank char after the name of the SCON
becomes the delimiter. So " can be used as usual, but anything else can
be used instead, e.g.:
scon <name> /this string contains " as non-delimiter/
*)
: SCON
<BUILDS bl skip-src+
src-start >in @ + c@ ,dlm-str
DOES> count ;
\ CASE should be used for non-contiguous or dynamically computed values.
\ This is a modified Eaker/Duncan model.
\ Our optimization strategy gives quite good code.
: CASE ?comp 302 ; immediate
: OF
postpone over postpone = postpone if
postpone drop ; immediate
: RANGEOF
postpone within? postpone if
postpone drop ; immediate
: ENDOF
postpone else ; immediate
: ENDCASE immediate
postpone drop
BEGIN dup 302 = NWHILE >resolve REPEAT drop ;
(* TYPE{ and ENUM{ (synonyms) define a Pascal/C-like enumerated type.
At this stage we don't give a name to the "type" as such, as we can't
do anything really sensible with it. However later we can optionally
load the ENUM-TYPE class which is rather more Pascal-like. But even
without that, the enumeration is very useful by itself.
*)
0 value TYPECNT
' null vect DO_ET \ Hook for handling the ENUM-TYPE
\ class when it's loaded
: ENDLIST? \ ( chr -- b )
latest n>count 1 = down c@ = and
dup IF latest n>link (forget) THEN ;
: TYPE{
0 -> typeCnt \ 1st value
BEGIN typeCnt constant 1 ++> typeCnt
& } endlist?
UNTIL
do_ET ;
: ENUM{ type{ ; \ C fans might like this name better
: ENUM gobble{ type{ ;
\ note we can't allow "type { ..." since "type" has another
\ meaning already. But "enum { ..." is OK.
type{ InMainDic InOtherMod InThisMod } \ Relocatable addr types
\ ========== Error diagnostics ===========
\ We use special values for nil handles and nil pointers. These are
\ odd addresses in ROM, so that if we do a word or long access we will
\ trap, and if we write a byte it at least won't go anywhere.
: .RTN \ ( addr -- )
cr ." From $" .h 4 spaces ;
: RANGE_ERR \ ( index range rtn-addr -- )
dup 1+ 0= ?error 128 \ Spurious range error
.rtn
dup -1 <
IF nip ?error 130 \ Not an indexed class
ELSE ." Range: " . ." Index: " .
true ?error 129
THEN ;
\ If we do software mult and div (on a 68000 which only allows a 16-bit divisor or
\ multiplicand) we also check for overflow and call ArithErr (vector) if ovfl occurs.
\ The appropriate err# is on the stack already, so here we just set ArithErr to Die.
\ This can be redirected as needed.
: X ['] range_err -> rngErr ['] die -> arithErr ;
x forget x
load Args